package com.axend.vetwavve.helper

import android.graphics.Canvas
import android.graphics.DashPathEffect
import android.graphics.Paint
import android.util.Log
import androidx.core.content.ContextCompat
import com.axend.lib_base.ext.runOnUIThread
import com.axend.lib_base.utils.CommUtils
import com.axend.vetwavve.R
import com.github.mikephil.charting.animation.ChartAnimator
import com.github.mikephil.charting.animation.Easing
import com.github.mikephil.charting.charts.LineChart
import com.github.mikephil.charting.components.XAxis
import com.github.mikephil.charting.data.Entry
import com.github.mikephil.charting.data.LineData
import com.github.mikephil.charting.data.LineDataSet
import com.github.mikephil.charting.interfaces.dataprovider.LineDataProvider
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet
import com.github.mikephil.charting.renderer.LineChartRenderer
import com.github.mikephil.charting.utils.EntryXComparator
import com.github.mikephil.charting.utils.MPPointD
import com.github.mikephil.charting.utils.ViewPortHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch
import java.lang.Math.PI
import java.lang.Math.abs
import java.util.Collections
import java.util.Timer
import java.util.TimerTask
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.ScheduledFuture
import java.util.concurrent.TimeUnit
import kotlin.math.sin
import kotlin.random.Random

/**
 * 图表帮助类
 */
object ChartHelper {

    /**
     * 集合最大存储数量
     */
    private const val maxCount = 60
    private var heartChartCounter = 0

    private var heartChartJob: Job? = null
    private var breathChartJob: Job? = null

    @Volatile
    private var waveValue: Double = 0.0

    @Volatile
    private var t: Double = 0.0



    @Volatile
    var heartYValue = 0f

    @Volatile
    var breathYValue = 0f


    var heartTimeMillis=150L
    var breathTimeMillis=150L

    var isStartHeartEcg=false
    var isStartBreathEcg=false

    /**
     * 初始化图表
     */
    fun initLineChart(
        mData: MutableList<Entry>,
        lineChart: LineChart,
        dataLineColor: Int,
        maxValue: Float,
        minValue: Float
    ) {
        /*图表初始化*/
        lineChart.apply {
            description.isEnabled = false // 移除描述
            isEnabled = false // 禁用触摸
            isDragEnabled = false // 禁止拖动
            setScaleEnabled(false) // 禁止缩放
            axisRight.isEnabled = false // 隐藏右侧Y轴
            axisLeft.isEnabled = false // 隐藏左侧Y轴
            xAxis.isEnabled = false // 隐藏X轴
            animateX(2000, Easing.EaseInOutCubic)
            animateY(2000, Easing.EaseInOutCubic)//心跳效果
            isHighlightPerTapEnabled = false
//            setMaxVisibleValueCount()
//            renderer = CustomCircleRenderer(this, this.animator, lineChart.viewPortHandler)
        }
        with(lineChart.xAxis) {
            position = XAxis.XAxisPosition.BOTTOM
            granularity = 0f // 设置标签间隔
            setDrawGridLines(false)
            setAvoidFirstLastClipping(true)
            textColor = android.graphics.Color.GRAY
        }

        with(lineChart.axisLeft) {
            granularity = 10f
            setDrawGridLines(false) // 不绘制网格线
            axisMinimum = minValue // 设置Y轴最小值
            axisMaximum = maxValue//设置Y轴最大值
            textColor = android.graphics.Color.GRAY
            textSize = 29f
            setLabelCount(4, true)
        }

        with(lineChart.legend) {
            /*关闭图例*/
            isEnabled = false
        }

        Collections.sort(mData, EntryXComparator())
        val lineData = LineData(getSet(mData, dataLineColor))
        lineData.setDrawValues(false)
        lineChart.data = lineData
        lineChart.invalidate()
        // 高亮显示最右端点
//        lineChart.highlightValue(lineData.entryCount - 1.toFloat(), 0)

    }


    /**
     * 更新图表数据
     */
    fun updateEntry(
        mData: MutableList<Entry>,
        mDashData: MutableList<Entry>,
        lineChart: LineChart,
        yValues: Float,
        color: Int,
        lineDataMode: LineDataSet.Mode = LineDataSet.Mode.CUBIC_BEZIER
    ) {
        with(lineChart.xAxis) {
            axisMinimum = 0f
            axisMaximum = maxCount.toFloat()
        }
        /*填满虚线循环maxCount*/
        val minValue = lineChart.axisLeft.mAxisMinimum
        val maxValue = lineChart.axisLeft.mAxisMaximum
        if (mDashData.size == 0 && mData.size == 0) {
            for (i in 0 until maxCount) {
                val entry = Entry(i.toFloat(), minValue)
                mDashData.add(entry)
            }
        }
        val dashedSet =
            getDashSet(mDashData, com.axend.lib_base.R.color.gray_level_four, lineDataMode)


        if (lineChart.data != null && lineChart.data.dataSetCount > 0) {
            when (mData.size) {
                0 -> {
                    val entry = Entry(maxCount.toFloat() - 0.5f, minValue)
                    mData.add(entry)
                }

                else -> {
                    var needRemove = false
                    for (e in mData) {
                        val x = e.x - 1f
                        if (x < 0f) needRemove = true
                        e.x = x
                    }
                    if (needRemove) mData.removeAt(0)
                    var filterValue =
                        if (yValues < minValue) minValue else if (yValues > maxValue) maxValue else yValues
                    val entry = Entry(maxCount.toFloat() - 0.5f, filterValue)
                    mData.add(entry)
                    if (mDashData.size > 0) mDashData.removeAt(mDashData.size - 1)
                }
            }
            val lineData = LineData(dashedSet, getSet(mData, color, lineDataMode))
            lineData.setDrawValues(false)
            lineChart.data = lineData
            lineChart.renderer =
                CustomCircleRenderer(lineChart, lineChart.animator, lineChart.viewPortHandler)
            lineChart.invalidate()

        }
    }

    /**
     * 心率图表动态
     * @param mData 数据集合
     */
    fun startHeartEcgChart(
        mData: MutableList<Entry>,
        lineChart: LineChart,
        color: Int,
        lineDataMode: LineDataSet.Mode = LineDataSet.Mode.CUBIC_BEZIER
    ) {
        with(lineChart.axisLeft) {
            axisMinimum = 50f // 设置Y轴最小值
            axisMaximum = 140f//设置Y轴最大值
        }
        val maxValue = lineChart.axisLeft.mAxisMaximum
        val minValue = lineChart.axisLeft.mAxisMinimum
        if (mData.size == 0 ) {
            for (i in 0 until maxCount) {
                val entry = Entry(i.toFloat(),  (maxValue + minValue) / 2)
                mData.add(entry)
            }
        }
        heartChartJob = CoroutineScope(Dispatchers.Main).launch {
            updateHeartChartFlow(lineChart).collect { randomNumber ->
                updateHeartChart(randomNumber, lineChart, mData, color, lineDataMode)
            }
        }
    }

    private fun updateHeartChartFlow(lineChart: LineChart): Flow<Float> = flow {

        val maxValue = lineChart.axisLeft.axisMaximum
        val minValue = lineChart.axisLeft.axisMinimum
        val randomValues = arrayOf(
            (maxValue + minValue) / 2,
            (maxValue + minValue) / 2,
            (maxValue + minValue) / 2,
            maxValue - 5,
            (maxValue + minValue) / 2 - 10,
            (maxValue + minValue) / 2,
            (maxValue + minValue) / 2
        )

        while (true) {
           if (isStartHeartEcg){
               val randomNumber = if (heartYValue > 0) {
                   if (heartChartCounter == randomValues.size) heartChartCounter = 0
                   randomValues[heartChartCounter++]
               } else {
                   (maxValue + minValue) / 2
               }
               emit(randomNumber)
               delay(heartTimeMillis)
           }
        }
    }

    private fun updateHeartChart(
        randomNumber: Float, lineChart: LineChart,
        mData: MutableList<Entry>,
        color: Int,
        lineDataMode: LineDataSet.Mode = LineDataSet.Mode.CUBIC_BEZIER
    ) {
        with(lineChart.xAxis) {
            axisMaximum = maxCount.toFloat()
        }

        when (mData.size) {
            0 -> {
                val entry = Entry(maxCount.toFloat() - 1, randomNumber)
                mData.add(entry)
            }

            else -> {
                var needRemove = false
                for (e in mData) {
                    val x = e.x - 1f
                    if (x < 0f) needRemove = true
                    e.x = x
                }
                if (needRemove) mData.removeAt(0)
                val entry = Entry(maxCount.toFloat() - 1, randomNumber)
                mData.add(entry)
            }
        }

        val lineData = LineData(
            getEcgSet(mData, color, lineDataMode)
                .apply {
                    cubicIntensity = 0.1f
                })

        lineChart.apply {
            renderer = CustomCircleRenderer(this, this.animator, viewPortHandler)
            data = lineData
            invalidate()
            data.notifyDataChanged()
            notifyDataSetChanged()
        }
    }


    fun updateBreathEcgChart(
        mData: MutableList<Entry>,
        lineChart: LineChart,
        color: Int,
        lineDataMode: LineDataSet.Mode = LineDataSet.Mode.CUBIC_BEZIER,
    ) {
        with(lineChart.xAxis) {
            axisMaximum = maxCount.toFloat()
        }
        with(lineChart.axisLeft) {
            axisMinimum = 8f // 设置Y轴最小值
            axisMaximum = 35f//设置Y轴最大值
        }
        val maxValue = lineChart.axisLeft.mAxisMaximum
        val minValue = lineChart.axisLeft.mAxisMinimum
        if (mData.size == 0 ) {
            for (i in 0 until maxCount) {
                val entry = Entry(i.toFloat(),  (maxValue + minValue) / 2)
                mData.add(entry)
            }
        }
        // 取消当前任务
        breathChartJob?.cancel()

        // 创建新的任务
        breathChartJob = CoroutineScope(Dispatchers.Main).launch {
            updateBreathChartFlow(lineChart, maxValue, minValue).collect { randomNumber ->
                updateBreathChart(randomNumber, lineChart, mData, color, lineDataMode)
            }
        }
    }

    private fun updateBreathChartFlow(
        lineChart: LineChart,
        maxValue: Float,
        minValue: Float,
    ): Flow<Float> = flow {
        while (true) {
            /*开始ecg*/
           if (isStartBreathEcg){
               val randomNumber: Float = if (breathYValue > 0) {
                   waveValue = (sin(t) + 1.0) / 2.0 // 正弦波范围 [0, 1]
                   // 增量调整
                   t += 0.5

                   // 防止 t 超过 2 * PI
                   if (t >= 2 * PI) {
                       t -= 2 * PI
                   }
                   // 生成一个[minValue, maxValue)范围内的随机数
                   (minValue + (maxValue - minValue) * waveValue).toFloat()
               } else {
                   // 取中间值
                   (maxValue + minValue) / 2
               }

               emit(randomNumber)
               delay(breathTimeMillis)
           }
        }
    }

    private fun updateBreathChart(
        randomNumber: Float,
        lineChart: LineChart,
        mData: MutableList<Entry>,
        color: Int,
        lineDataMode: LineDataSet.Mode = LineDataSet.Mode.CUBIC_BEZIER
    ) {
        with(lineChart.xAxis) {
            axisMaximum = maxCount.toFloat()
        }

        when (mData.size) {
            0 -> {
                val entry = Entry(maxCount.toFloat() - 1, randomNumber)
                mData.add(entry)
            }

            else -> {
                var needRemove = false
                for (e in mData) {
                    val x = e.x - 1f
                    if (x < 0f) needRemove = true
                    e.x = x
                }
                if (needRemove) mData.removeAt(0)
                val entry = Entry(maxCount.toFloat() - 1, randomNumber)
                mData.add(entry)
            }
        }

        val lineData = LineData(
            getEcgSet(mData, color, lineDataMode)
                .apply {
                    cubicIntensity = 0.0f
                })

        runOnUIThread {
            lineChart.apply {
                renderer =
                    CustomCircleRenderer(this, this.animator, lineChart.viewPortHandler)
                data = lineData
                invalidate()
                data.notifyDataChanged()
                notifyDataSetChanged()
            }
        }
    }

    /**
     * 结束折线图定时器
     */
    fun stopEcgChartTimer() {
        heartChartJob?.cancel()
        breathChartJob?.cancel()
    }

    /**
     * 温度ecg折线图
     */
    fun updateTempEcgChart(
        mData: MutableList<Entry>,
        lineChart: LineChart,
        yValues: Float,
        color: Int,
        lineDataMode: LineDataSet.Mode = LineDataSet.Mode.CUBIC_BEZIER
    ) {

//        var needRemove = lineChart.data.getDataSetByIndex(0).entryCount.toFloat() > maxCount
//        if (needRemove) mData.removeAt(0)

        val newEntry = Entry((lineChart.data.getDataSetByIndex(0).entryCount.toFloat()), yValues)
        mData.add(newEntry)

//        if (mData.size > maxCount) {
//            counter = 0
//            mData.clear()
//        }


//        val dataSet = LineDataSet(mData, "ECG")
//        dataSet.color = android.graphics.Color.BLUE
//        dataSet.setDrawValues(false)
//        dataSet.mode = LineDataSet.Mode.CUBIC_BEZIER
//        dataSet.cubicIntensity = 0.2f
//
//        val dataSets = mutableListOf<ILineDataSet>()
//        dataSets.add(dataSet)
//        lineChart.animateX(2000)

        val lineData = LineData(getSet(mData, color, lineDataMode)
            .apply {
                cubicIntensity = 0.5f
            })
        with(lineChart.xAxis) {
            resetAxisMaximum()
            resetAxisMinimum()
        }
        lineChart.apply {
//            renderer = CustomCircleRenderer(this, this.animator, lineChart.viewPortHandler)
            data = lineData
            notifyDataSetChanged()
            setVisibleXRangeMaximum(120f)
            moveViewToX(data.entryCount.toFloat())
//            invalidate()
        }


    }


    /**
     * 线条数据
     * 默认线条类型平滑曲线
     */
    private fun getSet(
        mData: MutableList<Entry>,
        resColor: Int,
        lineDataMode: LineDataSet.Mode = LineDataSet.Mode.CUBIC_BEZIER
    ): LineDataSet {
        return LineDataSet(mData, "").apply {
            color = ContextCompat.getColor(CommUtils.getContext(), resColor)
            lineWidth = 3f
            setDrawCircles(false) // 不绘制数据点圆圈
            mode = lineDataMode // 设置平滑曲线
            setDrawValues(false)
            setDrawCircleHole(false)
            isHighlightEnabled = true
//            cubicIntensity = 0.8f
            circleRadius = 4f // 设置圆圈半径
            disableDashedLine()
            setDrawFilled(false)
            setCircleColor(ContextCompat.getColor(CommUtils.getContext(), resColor))
//
        }
    }

    /**
     * ecg数据模拟
     */
    private fun getEcgSet(
        mData: MutableList<Entry>,
        resColor: Int,
        lineDataMode: LineDataSet.Mode = LineDataSet.Mode.CUBIC_BEZIER
    ): LineDataSet {
        return LineDataSet(mData, "").apply {
            color = ContextCompat.getColor(CommUtils.getContext(), resColor)
            lineWidth = 3f
            setDrawCircles(false) // 不绘制数据点圆圈
            mode = lineDataMode // 设置平滑曲线
            setDrawValues(false)
            setDrawCircleHole(false)
            isHighlightEnabled = false
//            cubicIntensity = 0.8f
            circleRadius = 4f // 设置圆圈半径
            disableDashedLine()
            setDrawFilled(false)
            setCircleColor(ContextCompat.getColor(CommUtils.getContext(), resColor))
//
        }
    }

    /**
     * 线条数据虚线
     */
    private fun getDashSet(
        mData: MutableList<Entry>,
        resColor: Int,
        lineDataMode: LineDataSet.Mode = LineDataSet.Mode.CUBIC_BEZIER
    ): LineDataSet {
        return LineDataSet(mData, "").apply {
            // 设置虚线效果
            enableDashedLine(5f, 5f, 0f)
            color = ContextCompat.getColor(CommUtils.getContext(), resColor)
            lineWidth = 10f
            setDrawFilled(true)
            setDrawCircles(false) // 不绘制数据点圆圈
            mode = lineDataMode// 设置平滑曲线

        }
    }


    // CustomCircleRenderer类
    class CustomCircleRenderer(
        dataSet: LineDataProvider,
        private val mAnimator: ChartAnimator?,
        private val mViewPortHandler: ViewPortHandler
    ) : LineChartRenderer(dataSet, mAnimator, mViewPortHandler) {

        override fun drawCircles(c: Canvas?) {
            super.drawCircles(c)
        }

        override fun drawData(c: Canvas) {
            super.drawData(c)
            // 获取数据集的所有条目
            val dataSet = mChart.data.dataSets
            for (i in 0 until dataSet.size) {
                var trans = mChart.getTransformer(dataSet[i].axisDependency)
                if (dataSet[i].entryCount > 0) {
                    val lastEntry = dataSet[i].getEntryForIndex(dataSet[i].entryCount - 1)
                    if (lastEntry != null) {
                        var mpPointD = trans.getPixelForValues(lastEntry.x, lastEntry.y)
                        lastEntry?.let {
                            drawCircle(
                                c,
                                it,
                                dataSet[i].color,
                                4f,
                                mpPointD
                            )
                        }
                    }

                }

            }
            // 只绘制最右侧的数据点圆圈
//            Log.d("ChartHelper drawData", "dataSet.entryCount:${dataSet.getIndexInEntries(dataSet.entryCount-1)}")

        }


        private fun drawCircle(
            c: Canvas,
            entry: Entry,
            circleColor: Int,
            radius: Float,
            mpPointD: MPPointD
        ) {
            val x = mpPointD.x.toFloat()
            val y = mpPointD.y.toFloat()
//            Log.d("ChartHelper drawCircle", "x:$x,y:$y")

            c.drawCircle(x, y, radius, Paint().apply {
                color = circleColor
                style = Paint.Style.FILL
            })
        }
    }

}